package com.hyb.hybmodulesoss.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.*;

import com.aliyun.vod.upload.impl.UploadVideoImpl;
import com.aliyun.vod.upload.req.UploadStreamRequest;
import com.aliyun.vod.upload.req.UploadVideoRequest;
import com.aliyun.vod.upload.resp.UploadStreamResponse;
import com.aliyun.vod.upload.resp.UploadVideoResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.vod.model.v20170321.DeleteVideoRequest;
import com.aliyuncs.vod.model.v20170321.DeleteVideoResponse;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoRequest;
import com.aliyuncs.vod.model.v20170321.GetPlayInfoResponse;

import com.ruoyi.common.core.exception.GlobalException;
import com.ruoyi.common.core.utils.Base64Utils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.uuid.IdUtils;
import com.ruoyi.common.core.web.domain.AjaxResult;
import com.ruoyi.common.security.annotation.InnerAuth;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
//import org.springframework.mock.web.MockMultipartFile;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.logging.SimpleFormatter;


@ConfigurationProperties(prefix = "spring.aliyun")
@RestController
public class SysOssController {

    @Value("${spring.aliyun.oss.keyId}")
    private String keyId;

    @Value("${spring.aliyun.oss.keySecret}")
    private String keySecret;

    @Value("${spring.aliyun.oss.endPoint}")
    private String endPoint;

    @Value("${spring.aliyun.oss.bucketName}")
    private String bucketName;

    @Value("${spring.aliyun.oss.templateGroupId}")
    private String templateGroupId;
    
    @Value("${spring.aliyun.oss.videoCateId}")
    private String videoCateId;

    @Value("${spring.aliyun.oss.ossUrl}")
    private String ossUrl;
    
    @Value("${spring.aliyun.oss.filePre}")
    private String filePre;

    @Value("${spring.aliyun.oss.textPre}")
    private String textPre;

    @InnerAuth
    @PostMapping(value="/upText")
    public AjaxResult upText(@RequestBody String s,@RequestParam("sub") String sub) throws IOException {
        JSONObject jsonObject = JSON.parseObject(s);
        Set<Map.Entry<String, Object>> entries = jsonObject.entrySet();
        String p="";
        for (Map.Entry<String, Object> entry : entries) {
            p= (String) entry.getValue();
        }
        InputStream inputStream = new ByteArrayInputStream(p.getBytes(StandardCharsets.UTF_8));
        MultipartFile file = new MockMultipartFile(ContentType.APPLICATION_OCTET_STREAM.toString(), inputStream);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(new Date());

        String fileName=format+IdUtils.fastUUID()+sub;
        String endpoint = endPoint;
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = keyId;
        String accessKeySecret = keySecret;
        // 填写Object完整路径，完整路径中不能包含Bucket名称，例如exampledir/exampleobject.txt。
        String objectName = textPre+fileName;


        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName,objectName,file.getInputStream());
            return AjaxResult.success().put("url","https://buuhyb123.oss-cn-guangzhou.aliyuncs.com/"+objectName);
        } catch (Exception oe) {
            throw new GlobalException("文件上传异常");
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }

    }

    @PostMapping(value = "/out/upFile")
    public AjaxResult outUpFile(@RequestPart MultipartFile file){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String format = simpleDateFormat.format(new Date());
        String fileName=format+IdUtils.fastUUID()+".png";
        String endpoint = endPoint;
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = keyId;
        String accessKeySecret = keySecret;
        // 填写Object完整路径，完整路径中不能包含Bucket名称，例如exampledir/exampleobject.txt。
        String objectName = filePre+fileName;


        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType(FileTypeUtils.getContentType(fileName.substring(fileName.lastIndexOf("."))));
            // 创建PutObject请求。
            ossClient.putObject(bucketName,objectName,file.getInputStream(),meta);
            // 如果上传成功，则返回200。
            Map<String,String> map=new HashMap<>();
            map.put("url", "https://buuhyb123.oss-cn-guangzhou.aliyuncs.com/"+objectName);
            map.put("href","https://buuhyb123.oss-cn-guangzhou.aliyuncs.com/"+objectName);
            return AjaxResult.success().put("data",map);
        } catch (Exception oe) {
            throw new GlobalException("图片上传异常");
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }


    //上传文件
    @InnerAuth
    @PostMapping(value = "/upFile")
    public AjaxResult upFile(@RequestParam("img") String img,@RequestParam(value = "fileName",required = false)String fileName) throws Exception {
        MultipartFile file = Base64Utils.base64ToMultipart(img);
        InputStream inputStream = file.getInputStream();
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = endPoint;
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessKeyId = keyId;
        String accessKeySecret = keySecret;
        // 填写Object完整路径，完整路径中不能包含Bucket名称，例如exampledir/exampleobject.txt。
        String objectName = filePre+fileName;
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName,objectName,inputStream);
            // 如果上传成功，则返回200。
            return AjaxResult.success().put("url",
                    "https://buuhyb123.oss-cn-guangzhou.aliyuncs.com/"+objectName);
        } catch (Exception oe) {
            throw new GlobalException("二维码上传异常，请联系管理员处理");
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
    //下载文件
    @InnerAuth
    @GetMapping("/downLoad")
    public AjaxResult downLoad(@RequestParam("path")String path,@RequestParam("fileName")String fileName) throws Exception {

        if(StringUtils.isEmpty(fileName)){
            return AjaxResult.error("文件名称不能为空");
        }
        if(StringUtils.isEmpty(path)){
            return AjaxResult.error("文件路径不能为空");
        }

        try{
            // 创建 OSSClient 实例
            OSS ossClient = new OSSClientBuilder().build(endPoint, keyId, keySecret);
            // 下载Object到本地文件，并保存到指定的本地路径中。如果指定的本地文件存在会覆盖，不存在则新建。
            // 如果未指定本地路径，则下载后的文件默认保存到示例程序所属项目对应本地路径中。
            String[] splits = fileName.split("/");
            StringBuilder filePath= new StringBuilder(path + "\\");
            //先创建一个文件夹
            File f=new File(filePath.toString());
            for (int i = 0; i < splits.length; i++) {
                if (i!=splits.length-1){
                    filePath.append(splits[i]).append("\\");
                }else{
                    //在获取完整路径之前,将所有文件夹创建好
                    filePath.append(splits[i]);
                }
            }
            //紧接着一层一层创建没有的文件夹或文件
            String[] strings = filePath.toString().split("\\\\");
            if (strings.length>10){
                return AjaxResult.error("你创建的文件夹层数过多");
            }
            StringBuilder str=new StringBuilder();
            for (int i=0;i<strings.length;i++) {
                if (i!=0){
                    str.append("//").append(strings[i]);
                }else{
                    str.append(strings[i]);
                }
                File ff=new File(str.toString());
                if(i!=strings.length-1){
                    if (!ff.exists()){
                        ff.mkdir();
                    }
                }
            }
            //获取到完整路径后,创建该文件
            File file = new File(str.toString());
            if (!file.exists()){
                file.createNewFile();
            }
            ossClient.getObject(new GetObjectRequest(bucketName, filePre+fileName),file);

            // 关闭OSSClient。
            ossClient.shutdown();
        }catch (Exception e){
            throw new Exception("未知异常");
        }

        return AjaxResult.success();
    }



    @GetMapping("/policy")
    public AjaxResult policy() {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessId = keyId;
        String accessKey = keySecret;
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = endPoint;
        // 填写Bucket名称，例如examplebucket。
        String bucket = bucketName;
        // 填写Host地址，格式为https://bucketname.endpoint。
        String host = "https://" + bucket + "." + endpoint;
        // 设置上传回调URL，即回调服务器地址，用于处理应用服务器与OSS之间的通信。OSS会在文件上传完成后，把文件上传信息通过此回调URL发送给应用服务器。
        // 设置上传到OSS文件的前缀，可置空此项。置空后，文件将上传至Bucket的根目录下。
        String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        String dir = filePre + format;

        // 创建ossClient实例。
        Map<String, String> respMap = null;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessId", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
            // respMap.put("expire", formatISO8601Date(expiration));
        } catch (Exception e) {
            return AjaxResult.error("服务器出现错误,请重新上传!");
        }
        return AjaxResult.success("data",respMap);
    }

    @DeleteMapping("/del")
    public AjaxResult deleteFile(@RequestParam("filePath") String filePath) {
        // 阿里云账号AccessKey拥有所有API的访问权限，风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维，请登录RAM控制台创建RAM用户。
        String accessId = keyId;
        String accessKey = keySecret;
        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
        String endpoint = endPoint;
        // 填写Bucket名称，例如examplebucket。
        String bucket = bucketName;
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessId, accessKey);
        String aliPath = filePath.replace(ossUrl, "");
        boolean exist = ossClient.doesObjectExist(bucket, aliPath);
        if (!exist) {
            return AjaxResult.error("文件不存在!");
        }

        ossClient.deleteObject(bucket, aliPath);
        ossClient.shutdown();
        return AjaxResult.success("文件已经删除!");
    }

    @PostMapping("/video")
    public AjaxResult upVideo(@RequestPart  MultipartFile file) throws IOException {
        String accessId = keyId;
        String accessKey = keySecret;

        UploadStreamResponse video = testUploadStream(accessId, accessKey, "测试", file.getOriginalFilename(),file.getInputStream());

        if (video.isSuccess()){
            return AjaxResult.success().put("videoId",video.getVideoId()).put("videoName",file.getOriginalFilename());
        }else{
            return AjaxResult.error("文件上传失败");
        }
    }

    private UploadStreamResponse testUploadStream(String accessKeyId, String accessKeySecret, String title, String fileName, InputStream inputStream) {
        UploadStreamRequest request = new UploadStreamRequest(accessKeyId, accessKeySecret, title, fileName, inputStream);
        /* 是否使用默认水印（可选），指定模板组ID时，根据模板组配置确定是否使用默认水印*/
        //request.setShowWaterMark(true);
        /* 自定义消息回调设置及上传加速设置（可选）, Extend为自定义扩展设置，MessageCallback为消息回调设置，AccelerateConfig为上传加速设置（上传加速功能需要先申请开通后才能使用）*/
        //request.setUserData("{\"Extend\":{\"test\":\"www\",\"localId\":\"xxxx\"},\"MessageCallback\":{\"CallbackType\":\"http\",\"CallbackURL\":\"http://example.aliyundoc.com\"},\"AccelerateConfig\":{\"Type\":\"oss\",\"Domain\":\"****Bucket.oss-accelerate.aliyuncs.com\"}}");
        /* 视频分类ID（可选） */
        request.setCateId(Long.valueOf(videoCateId));
        /* 视频标签，多个用逗号分隔（可选） */
        //request.setTags("标签1,标签2");
        /* 视频描述（可选）*/
        //request.setDescription("视频描述");
        /* 封面图片（可选）*/
        //request.setCoverURL("http://cover.example.com/image_01.jpg");
        /* 模板组ID（可选）*/
        request.setTemplateGroupId(templateGroupId);
        //request.setTemplateGroupId("8c4792cbc8694e7084fd5330e56****");
        /* 工作流ID（可选）*/
        //request.setWorkflowId("d4430d07361f0*be1339577859b0****");
        /* 存储区域（可选）*/
        //request.setStorageLocation("in-201703232118266-5sejd****.oss-cn-shanghai.aliyuncs.com");
        /* 开启默认上传进度回调 */
//         request.setPrintProgress(true);
        /* 设置自定义上传进度回调（必须继承 VoDProgressListener） */
        /*默认关闭。如果开启了这个功能，上传过程中服务端会在日志中返回上传详情。如果不需要接收此消息，需关闭此功能*/
//         request.setProgressListener(new VoDProgressListener() {
//             @Override
//             public void onVidReady(String s) {
//                 System.out.println(s);
//             }
//
//             @Override
//             public void onImageIdReady(String s) {
//                 System.out.println(s);
//             }
//
//             @Override
//             public void progressChanged(ProgressEvent progressEvent) {
//                 System.out.println(progressEvent.toString());
//             }
//         });
        /* 设置应用ID*/
        //request.setAppId("app-100****");
        /* 点播服务接入点 */
        //request.setApiRegionId("cn-shanghai");
        /* ECS部署区域*/
        // request.setEcsRegionId("cn-shanghai");
        UploadVideoImpl uploader = new UploadVideoImpl();
        return uploader.uploadStream(request);
    }

    private UploadVideoResponse testUploadVideo(String accessKeyId, String accessKeySecret, String title, String fileName) {

        UploadVideoRequest request = new UploadVideoRequest(accessKeyId, accessKeySecret, title, fileName);
        /* 可指定分片上传时每个分片的大小，默认为2M字节 */
        request.setPartSize(2 * 1024 * 1024L);
        /* 可指定分片上传时的并发线程数，默认为1，（注：该配置会占用服务器CPU资源，需根据服务器情况指定）*/
        request.setTaskNum(1);
    /* 是否开启断点续传, 默认断点续传功能关闭。当网络不稳定或者程序崩溃时，再次发起相同上传请求，可以继续未完成的上传任务，适用于超时3000秒仍不能上传完成的大文件。
    注意：断点续传开启后，会在上传过程中将上传位置写入本地磁盘文件，影响文件上传速度，请您根据实际情况选择是否开启*/
        //request.setEnableCheckpoint(false);
        /* OSS慢请求日志打印超时时间，是指每个分片上传时间超过该阈值时会打印debug日志，如果想屏蔽此日志，请调整该阈值。单位：毫秒，默认为300000毫秒*/
        //request.setSlowRequestsThreshold(300000L);
        /* 可指定每个分片慢请求时打印日志的时间阈值，默认为300s*/
        //request.setSlowRequestsThreshold(300000L);
        /* 是否显示水印（可选），指定模板组ID时，根据模板组配置确定是否显示水印*/
        //request.setIsShowWaterMark(true);
        /* 自定义消息回调设置及上传加速设置（可选）, Extend为自定义扩展设置，MessageCallback为消息回调设置，AccelerateConfig为上传加速设置（上传加速功能需要先申请开通后才能使用）*/
        //request.setUserData("{\"Extend\":{\"test\":\"www\",\"localId\":\"xxxx\"},\"MessageCallback\":{\"CallbackType\":\"http\",\"CallbackURL\":\"http://example.aliyundoc.com\"},\"AccelerateConfig\":{\"Type\":\"oss\",\"Domain\":\"****Bucket.oss-accelerate.aliyuncs.com\"}}");
        /* 视频分类ID（可选） */
        request.setCateId(Long.valueOf(videoCateId));
        /* 视频标签，多个用逗号分隔（可选） */
        //request.setTags("标签1,标签2");
        /* 视频描述（可选）*/
        //request.setDescription("视频描述");
        /* 封面图片（可选）*/
        //request.setCoverURL("http://cover.example.com/image_01.jpg");
        /* 模板组ID（可选）*/
        request.setTemplateGroupId(templateGroupId);
        /* 工作流ID（可选）*/
        //request.setWorkflowId("d4430d07361f0*be1339577859b0****");
        /* 存储区域（可选）*/
        //request.setStorageLocation("in-201703232118266-5sejd****.oss-cn-shanghai.aliyuncs.com");
        /* 开启默认上传进度回调 */
        //request.setPrintProgress(false);
        /* 设置自定义上传进度回调（必须继承 VoDProgressListener）*/
        /*默认关闭。如果开启了这个功能，上传过程中服务端会在日志中返回上传详情。如果不需要接收此消息，需关闭此功能*/
        //request.setProgressListener(new PutObjectProgressListener());
        /* 设置您实现的生成STS信息的接口实现类*/
        // request.setVoDRefreshSTSTokenListener(new RefreshSTSTokenImpl());
        /* 设置应用ID*/
        //request.setAppId("app-100****");
        /* 点播服务接入点 */
        //request.setApiRegionId("cn-shanghai");
        /* ECS部署区域*/
        // request.setEcsRegionId("cn-shanghai");
        UploadVideoImpl uploader = new UploadVideoImpl();
        return uploader.uploadVideo(request);
//        UploadVideoResponse response = uploader.uploadVideo(request);
//        System.out.print("RequestId=" + response.getRequestId() + "\n");  //请求视频点播服务的请求ID
//        if (response.isSuccess()) {
//            System.out.print("VideoId=" + response.getVideoId() + "\n");
//        } else {
//            /* 如果设置回调URL无效，不影响视频上传，可以返回VideoId同时会返回错误码。其他情况上传失败时，VideoId为空，此时需要根据返回错误码分析具体错误原因 */
//            System.out.print("VideoId=" + response.getVideoId() + "\n");
//            System.out.print("ErrorCode=" + response.getCode() + "\n");
//            System.out.print("ErrorMessage=" + response.getMessage() + "\n");
//        }
    }

    @GetMapping("/getVideo")
    public AjaxResult getVideo(@RequestParam("videoId")String videoId){
        DefaultAcsClient client = null;
        List<String> list=null;
        GetPlayInfoResponse response = new GetPlayInfoResponse();
        try {
            client = initVodClient(keyId,
                    keySecret);
            response = getPlayInfo(client,videoId);
            List<GetPlayInfoResponse.PlayInfo> playInfoList = response.getPlayInfoList();
            //播放地址
            list=new ArrayList<>();
            for (GetPlayInfoResponse.PlayInfo playInfo : playInfoList) {
                list.add(playInfo.getPlayURL());
            }
            //Base信息
            System.out.print("VideoBase.Title = " + response.getVideoBase().getTitle() + "\n");
        } catch (Exception e) {
            return AjaxResult.error("视频转码中,请稍后获取!");
        }
        System.out.print("RequestId = " + response.getRequestId() + "\n");
        return AjaxResult.success()
                .put("urls",list)
                .put("videTitle",response.getVideoBase().getTitle())
                .put("requestId",response.getRequestId());
    }

    @DeleteMapping("/delVideo")
    public AjaxResult delVideo(@RequestParam("videoId") String videoId) throws Exception {
        String accessId = keyId;
        String accessKey = keySecret;
        DefaultAcsClient client = initVodClient(accessId, accessKey);
        try {
            deleteVideo(client,videoId);
            return AjaxResult.success();
        } catch (Exception e) {
            return AjaxResult.error("删除失败,请重新尝试!");
        }
    }

    //填入AccessKey信息
    public static DefaultAcsClient initVodClient(String accessKeyId, String accessKeySecret) throws Exception {
        String regionId = "cn-shanghai";  // 点播服务接入地域
        DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
        return new DefaultAcsClient(profile);
    }

    /*获取播放地址函数*/
    public static GetPlayInfoResponse getPlayInfo(DefaultAcsClient client,String videoId) throws Exception {
        GetPlayInfoRequest request = new GetPlayInfoRequest();
        request.setVideoId(videoId);
        return client.getAcsResponse(request);
    }

    public static DeleteVideoResponse deleteVideo(DefaultAcsClient client,String videoId) throws Exception {
        DeleteVideoRequest request = new DeleteVideoRequest();
        //支持传入多个视频ID，多个用逗号分隔
        request.setVideoIds(videoId);
        return client.getAcsResponse(request);
    }

}
